package creationalPatterns.singleton;

public class SingletonPattern {
    // 使用volatile主要是为了防止指令重排序。
    // 在new SingletonPattern()的时候，其实是分为三步：
    // 1. 分配内存空间
    // 2. 初始化对象
    // 3. 将instance指向分配的内存地址
    // 但是由于JVM具有指令重排的特性，有可能执行顺序变为了1->3->2，这在单线程情况下自然是没有问题。
    // 但如果是多线程下，可能会导致某个线程获得还没有初始化的实例。如线程A执行了1和3，此时instance已经不为空了，但其实这个instance并没有初始化完成。
    // 如果线程二获取instance，则会返回一个没有初始化完成的instance。从而有程序错误的风险。

    // 赋值为null,AI的解释是明确表达出延迟加载的意图。因为不赋值类加载时也会初始化为null
    private static volatile SingletonPattern instance = null;

    // 私有构造方法，防止被外部实例化
    private SingletonPattern() {
    }

    public static SingletonPattern getInstance() {
        //第一次检查，bean没有创建，才加锁，提高性能
        if (instance == null) {
            synchronized (SingletonPattern.class) {
                // 第二次检查是为了防止多线程下创建多个实例。
                if (instance == null) {
                    instance = new SingletonPattern();
                    System.out.println("创建了一个实例");
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            SingletonPattern singleton = SingletonPattern.getInstance();
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            SingletonPattern singleton = SingletonPattern.getInstance();
        });
        t2.start();
    }

}
